#pragma once
#include <vector>
#include <string>
#include <set>
#include <unordered_map>
#include <list>
#include <map>
#include <queue>
using namespace std;

const int kMaxFuncNum = 1024;
const int kMaxBlockNum = 1024;
const int kMaxInsNumPerBlock = 2048;

const int kMaxLineLength = 1024;
const int kMaxWordLength = 1024;


// the type of an instruction
// -1: default
// 0: label
// 1: instructions in the reference file
enum class InsType
{
	Default = -1,
	Label, // 0
	ReferIns // 1
};


// data structure for instructions
struct Instruction
{
	// the type of an instruction
	InsType type;
	// the entire string of original instruction
	char* ins_string;
	// the name of an instruction
	char ins_name[16];
	// function unit of an instruction
	string cond_field;
	// 3 input (at most) of an instruction
	string input[3];
	// 1 output of an instruction
	string output;
	// ? 
	string note;
	// 0. denote whether ! the cond_field
	// 1. for loop end label, loop_unrolling factor
	int cond_flag;
	

	
	// construct function
	Instruction() {
		type = InsType::Default;
		ins_string = NULL;
		ins_name[0] = '\0';
		cond_field = "";
		cond_flag = 0;
		input[0] = "";
		input[1] = "";
		input[2] = "";
		output = "";
		note = "";
	}
};


// 0: normal label
// 1: loop start label
// 2: instructions
// 3: loop end label
enum class BlockType
{
	Default = -1,  // -1
	Label,  // 0
	LoopStart, // 1
	Instruction, // 2
	LoopEnd, //3
	Close,
	Open,

};
// data structure for basic block 
struct Block
{
	// used to denote the type of a code block
	BlockType type;
	// the label/name of the block
	// default: ""
	//
	string label;
	// used to denote the index of a code block
	// starts from 0
	int block_index;
	// used to denote the depth of a loop
	// default -1
	int loop_depth;
	// used to denote the number of instructions in block
	int block_ins_num;
	Instruction block_ins[kMaxInsNumPerBlock];
	vector<Instruction*> ins_pointer_list;

	Block() {
		type = BlockType::Default;
		block_index = -1;
		block_ins_num = 0;
		loop_depth = 0;
		label = "";
	}
};


// data structure for the function
struct Function
{
	// total number of blocks
	int total_block_num;

	string function_name;

	// used to denote the index of a code block
	// starts from 0
	int function_index;

	// list of the blocks
	Block function_block[kMaxBlockNum];
	vector<Block*> block_pointer_list;


	Function() {
		total_block_num = 0;
	}
};


// data structure for the module
struct Module
{
	// total number of functions
	int total_function_num;
	
	// list of the functions
	Function module_function[kMaxFuncNum];
	vector<Function*> function_pointer_list;

	
	Module() {
		total_function_num = 0;
	}
};

void CleanModule();